package com.cvte.boe.media.utils;

import android.os.IBinder;

import com.cvte.boe.media.model.ExtraInfoModel;

import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
//import android.os.SystemProperties;

public class MountListUtil {

    private MountListUtil() {
    }

    private static MountListUtil single = null;

    public synchronized static MountListUtil getInstance() {
        if (single == null) {
            single = new MountListUtil();
        }
        return single;
    }

    private final String TAG = MountListUtil.this.getClass().getSimpleName();
    private List<ExtraInfoModel> mountInfoList = new ArrayList();
    private Map<String, ExtraInfoModel> mountMap = new HashMap<>();

    private static final String ExternalPrimaryPath = System.getenv("EXTERNAL_STORAGE");

    public boolean isValidPath(String path) {
        if ((path == null) || (mountInfoList == null)) {
            LogUtil.e(TAG, "MountInfoModelExt mountInfoList == null");
            return true;
        }
        for (int i = 0x0; i < mountInfoList.size(); i = i + 0x1) {
            Object info = mountInfoList.get(i);
            if ((info != null)) {
                Object mMountPoint = getFieldValue("mMountPoint", info);
                if (mMountPoint != null && path.equals(mMountPoint)) {
                    LogUtil.d(TAG, "MountInfoModelExt mMountPoint info:" + mMountPoint.toString());
                    return true;
                }
            }
        }
        return false;
    }

    public void initMountInfoList() {
        mountInfoList.clear();
        mountMap.clear();
        try {
            Class<?> cls = Class.forName("android.os.ServiceManager");
            if (cls != null) {
                Class<?>[] paraTypes = new Class<?>[]{String.class};
                Method method = cls.getMethod("getService", paraTypes);
                if (method != null) {
                    Object service = method.invoke(cls, new Object[]{"mount"});
                    if (service != null) {
                        Class<?> clsMouseManager = Class.forName("android.os.storage.IMountService$Stub");
                        Class[] paraTypesX = new Class[]{IBinder.class};
                        Method asInterfaceMethod = clsMouseManager.getMethod("asInterface", paraTypesX);
                        if (asInterfaceMethod != null) {
                            Object mountManager = asInterfaceMethod.invoke(asInterfaceMethod, new Object[]{service});
                            if (mountManager != null) {
                                Method getVolumeList = mountManager.getClass().getMethod("getVolumeList", new Class[0]);
                                if (getVolumeList != null) {
                                    Object obj = getVolumeList.invoke(mountManager, new Object[0]);
                                    if (obj != null) {
                                        Object[] tempArray = (Object[]) obj;
                                        mountInfoList.clear();
                                        for (Object info : tempArray) {
                                            // cvte shiqiankun @ 20151228 modified start
                                            Method getFatVolumeId = info.getClass().getMethod("getFatVolumeId", new Class[0]);
                                            Object fatVolumeId = getFatVolumeId.invoke(info, new Object[0]);
                                            int fatVolumeIdInt = fatVolumeId == null ? -1 : Integer.parseInt(fatVolumeId.toString());
                                            File mountFile = (File) getFieldValue("mPath", info);
                                            if (mountFile == null)
                                                continue;
                                            String path = mountFile.getAbsolutePath();
                                            String parent = path.substring(0, path.lastIndexOf("/") - 1);
                                            ExtraInfoModel model = new ExtraInfoModel();
                                            model.setUUID((String) getFieldValue("mUuid", info));
                                            Object objUserLabel = getFieldValue("mUserLabel", info);
                                            // remove the umounted device
                                            Object obStringStatus = getFieldValue("mState", info);
                                            if("unmounted".equals(obStringStatus) && !ExternalPrimaryPath.equals(path)){
                                                continue;
                                            }
                                            if(ExternalPrimaryPath.equals(path)){
                                                continue;
                                            }
                                            String label = objUserLabel == null || StringUtils.isEmpty(objUserLabel.toString()) || fatVolumeIdInt == -1 ? "" : EncodeUtil.getUSBname(objUserLabel.toString());
                                            label = label == null || label.equalsIgnoreCase("null") || label.contains("?") ? "" : label;
                                            model.setLabel(label);
                                            model.setDiskLabel(path.substring(path.lastIndexOf("/") + 1));
                                            model.setMountPoint(path);
                                            model.setDevType(parent.substring(parent.lastIndexOf("/") + 1));
                                            model.setDevNode((int) mountFile.lastModified());
                                            mountInfoList.add(model);
                                            mountMap.put(path, model);
                                            // cvte shiqiankun @ 20151228 modified end
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    /**
     * Mount external storage at given mount point. Returns an int
     * consistent with MountServiceResultCode
     *
     * @param mountPoint
     * @return
     */
    public int doMountVolume(String mountPoint) {
        try {
            LogUtil.d(TAG, "MountInfoModelExt doMountVolume() begin invoke!");
            Class<?> cls = Class.forName("android.os.ServiceManager");
            if (cls != null) {
                Class<?>[] paraTypes = new Class<?>[]{String.class};
                Method method = cls.getMethod("getService", paraTypes);
                if (method != null) {
                    Object service = method.invoke(cls, new Object[]{"mount"});
                    LogUtil.d(TAG, "MountInfoModelExt getService() service :" + service);
                    if (service != null) {
                        Class<?> clsMouseManager = Class.forName("android.os.storage.IMountService$Stub");
                        Class[] paraTypesX = new Class[]{IBinder.class};
                        Method asInterfaceMethod = clsMouseManager.getMethod("asInterface", paraTypesX);
                        LogUtil.d(TAG, "MountInfoModelExt asInterface method :" + asInterfaceMethod);
                        if (asInterfaceMethod != null) {
                            Object mountManager = asInterfaceMethod.invoke(asInterfaceMethod, new Object[]{service});
                            LogUtil.d(TAG, "MountInfoModelExt mountManager :" + mountManager);
                            if (mountManager != null) {
                                Method mountVolume = mountManager.getClass().getMethod("mountVolume", String.class);
                                LogUtil.d(TAG, "MountInfoModelExt doMountVolume() method : " + mountVolume);
                                if (mountVolume != null) {
                                    Object obj = mountVolume.invoke(mountManager, mountPoint);
                                    return obj == null ? -1 : Integer.parseInt(obj.toString());
                                }
                            }
                        }
                    }
                }
            }
        } catch (ClassNotFoundException e) {
            LogUtil.e(TAG, "MountInfoModelExt doMountVolume");
        } catch (SecurityException e) {
            LogUtil.e(TAG, "MountInfoModelExt doMountVolume");
        } catch (NoSuchMethodException e) {
            LogUtil.e(TAG, "MountInfoModelExt doMountVolume");
        } catch (IllegalArgumentException e) {
            LogUtil.e(TAG, "MountInfoModelExt doMountVolume");
        } catch (IllegalAccessException e) {
            LogUtil.e(TAG, "MountInfoModelExt doMountVolume");
        } catch (InvocationTargetException e) {
            LogUtil.e(TAG, "MountInfoModelExt doMountVolume");
        }
        return -1;
    }

    /**
     * Safely unmount external storage at given mount point. The unmount
     * is an asynchronous operation. Applications should register
     * StorageEventListener for storage related status changes.
     *
     * @param mountPoint
     * @param force
     * @param removeEncryption
     * @return
     */
    public int doUnmountVolume(String mountPoint, boolean force, boolean removeEncryption) {
        try {
            LogUtil.d(TAG, "MountInfoModelExt doUnmountVolume() begin invoke!");
            Class<?> cls = Class.forName("android.os.ServiceManager");
            if (cls != null) {
                Class<?>[] paraTypes = new Class<?>[]{String.class};
                Method method = cls.getMethod("getService", paraTypes);
                if (method != null) {
                    Object service = method.invoke(cls, new Object[]{"mount"});
                    LogUtil.d(TAG, "MountInfoModelExt getService() service :" + service);
                    if (service != null) {
                        Class<?> clsMouseManager = Class.forName("android.os.storage.IMountService$Stub");
                        Class[] paraTypesX = new Class[]{IBinder.class};
                        Method asInterfaceMethod = clsMouseManager.getMethod("asInterface", paraTypesX);
                        LogUtil.d(TAG, "MountInfoModelExt asInterface method :" + asInterfaceMethod);
                        if (asInterfaceMethod != null) {
                            Object mountManager = asInterfaceMethod.invoke(asInterfaceMethod, new Object[]{service});
                            LogUtil.d(TAG, "MountInfoModelExt mountManager :" + mountManager);
                            if (mountManager != null) {
                                Method unmountVolume = mountManager.getClass().getMethod("unmountVolume", String.class, boolean.class, boolean.class);
                                LogUtil.d(TAG, "MountInfoModelExt doUnmountVolume() method : " + unmountVolume);
                                if (unmountVolume != null) {
                                    Object obj = unmountVolume.invoke(mountManager, mountPoint, force, removeEncryption);
                                    LogUtil.d(TAG, "MountInfoModelExt doUnmountVolume.invoke result: " + obj);
                                    return obj == null ? -1 : Integer.parseInt(obj.toString());
                                }
                            }
                        }
                    }
                }
            }
        } catch (ClassNotFoundException e) {
            LogUtil.e(TAG, "MountInfoModelExt doUnmountVolume");
        } catch (SecurityException e) {
            LogUtil.e(TAG, "MountInfoModelExt doUnmountVolume");
        } catch (NoSuchMethodException e) {
            LogUtil.e(TAG, "MountInfoModelExt doUnmountVolume");
        } catch (IllegalArgumentException e) {
            LogUtil.e(TAG, "MountInfoModelExt doUnmountVolume");
        } catch (IllegalAccessException e) {
            LogUtil.e(TAG, "MountInfoModelExt doUnmountVolume");
        } catch (InvocationTargetException e) {
            LogUtil.e(TAG, "MountInfoModelExt doUnmountVolume");
        }
        return -1;
    }

    /**
     * Gets the state of a volume via its mountpoint.
     *
     * @param mountPoint
     * @return state: mounted or other
     */
    public String getVolumeState(String mountPoint) {
        try {
            LogUtil.d(TAG, "MountInfoModelExt getVolumeState() begin invoke!");
            Class<?> cls = Class.forName("android.os.ServiceManager");
            if (cls != null) {
                Class<?>[] paraTypes = new Class<?>[]{String.class};
                Method method = cls.getMethod("getService", paraTypes);
                if (method != null) {
                    Object service = method.invoke(cls, new Object[]{"mount"});
                    LogUtil.d(TAG, "MountInfoModelExt getService() service :" + service);
                    if (service != null) {
                        Class<?> clsMouseManager = Class.forName("android.os.storage.IMountService$Stub");
                        Class[] paraTypesX = new Class[]{IBinder.class};
                        Method asInterfaceMethod = clsMouseManager.getMethod("asInterface", paraTypesX);
                        LogUtil.d(TAG, "MountInfoModelExt asInterface method :" + asInterfaceMethod);
                        if (asInterfaceMethod != null) {
                            Object mountManager = asInterfaceMethod.invoke(asInterfaceMethod, new Object[]{service});
                            LogUtil.d(TAG, "MountInfoModelExt getVolumeState :" + mountManager);
                            if (mountManager != null) {
                                Method volumeState = mountManager.getClass().getMethod("getVolumeState", String.class);
                                LogUtil.d(TAG, "MountInfoModelExt getVolumeState() method : " + volumeState);
                                if (volumeState != null) {
                                    Object obj = volumeState.invoke(mountManager, mountPoint);
                                    return obj == null ? null : obj.toString();
                                }
                            }
                        }
                    }
                }
            }
        } catch (ClassNotFoundException e) {
            LogUtil.e(TAG, "MountInfoModelExt getVolumeState");
        } catch (SecurityException e) {
            LogUtil.e(TAG, "MountInfoModelExt getVolumeState");
        } catch (NoSuchMethodException e) {
            LogUtil.e(TAG, "MountInfoModelExt getVolumeState");
        } catch (IllegalArgumentException e) {
            LogUtil.e(TAG, "MountInfoModelExt getVolumeState");
        } catch (IllegalAccessException e) {
            LogUtil.e(TAG, "MountInfoModelExt getVolumeState");
        } catch (InvocationTargetException e) {
            LogUtil.e(TAG, "MountInfoModelExt getVolumeState");
        }
        return null;
    }

    public List<ExtraInfoModel> getExtraInfoList() {
        if ((mountInfoList == null) || (mountInfoList.size() == 0)) {
            LogUtil.e(TAG, "MountInfoModelExt getExtraInfoList return null.");
            return new ArrayList<ExtraInfoModel>();
        }
        return mountInfoList;
    }

    public ExtraInfoModel getExtraInfoModel(String mountPath) {
        ExtraInfoModel model = mountMap.get(mountPath);
        if (model == null && mountPath.lastIndexOf("/") == mountPath.length() - 1) {
            model = mountMap.get(mountPath.substring(0, mountPath.lastIndexOf("/")));
        }
        return model;
    }

    /**
     * 通过反射获取字段值
     *
     * @param propertyName 属性名
     * @param obj          实例对象
     * @return 属性值
     */
    private Object getFieldValue(String propertyName, Object obj) {
        try {
            Field field = obj.getClass().getDeclaredField(propertyName);
            field.setAccessible(true);
            return field.get(obj);
        } catch (Exception ex) {
            LogUtil.e(TAG, "MountInfoModelExt getFieldValue");
        }
        return null;
    }
}
